#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>

#include "usbmonitor.h"

#define UEVENT_BUFFER_MAX       (1024*15)   //15K

UsbMonitor::UsbMonitor(QObject *parent) :
    QThread(parent)
{
    m_isStop = false;
}

//bool UsbMonitor::start()
//{
//    usbmonitor();           //ivan 应该有线程处理
//}

void UsbMonitor::stop()
{
    m_isStop = true;
}

void UsbMonitor::usbmonitor()
{
#ifdef Q_OS_LINUX
    char apcRecBuf[UEVENT_BUFFER_MAX];
    bzero(&apcRecBuf, UEVENT_BUFFER_MAX);
    int aiHotplug_sock= 0;

    /*
    int aiResult= 0;

    const int buffersize = 1024 ;      //1K

    struct sockaddr_nl astNLaddr;

    memset(&astNLaddr, 0x00, sizeof(struct sockaddr_nl));
    astNLaddr.nl_family = AF_NETLINK;
    astNLaddr.nl_pid = getpid();
    astNLaddr.nl_groups = 1;
    aiHotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    setsockopt(aiHotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
    aiResult = bind(aiHotplug_sock, (struct sockaddr *) &astNLaddr, sizeof(struct sockaddr_nl));
    */
    aiHotplug_sock = initsock();

    while(1)
    {
        if (m_isStop)
            break;

        bzero(&apcRecBuf, UEVENT_BUFFER_MAX);
        recv(aiHotplug_sock, &apcRecBuf, sizeof(apcRecBuf), 0);
//        printf("%s\n", apcRecBuf);

        char driver[50] = {0};
        char mount[50] = {0};
        char userMount[50] ={0};
        if(getdriver(apcRecBuf, driver))
        {
            //决定让系统自动挂载的次数，一般最好不超过
            int ncount = 3;
            bool bmount = false;
//            int waitStatus;
            while(ncount>0)
            {
                bmount = getmount(driver, mount);
                strcpy(userMount, driver);
                if(bmount)    //找不到有两个可能，1.还未加载完成；2.加载不成功
                {
                    emit usbChange(0, mount);
                    break;
                }

                sleep(1);
                ncount--;
            }

            if(!bmount)     //ncount秒内没加载成功,那么进行程序挂载
            {
                pid_t child;
                getuid();
//                    setuid(1000);
                QString mountPath = QCoreApplication::applicationDirPath() + "/usb";
                QDir dir(mountPath);
                if (!dir.exists())
                {
                    dir.mkdir(mountPath);
                }

                QFileInfoList list = dir.entryInfoList();
                if (list.count() > 2)
                {
                    QString appendPath = QTime::currentTime().toString("/hhmmss");
                    mountPath.append(appendPath);
                    dir.setPath(mountPath);
                    if (!dir.exists())
                    {
                        dir.mkdir(mountPath);
                    }
                }
                child = fork();
                if (child == 0)
                {
                    char mountBuf[128] = {0};
                    strcpy(mountBuf, mountPath.toLatin1().data());

                    //exec函数，调用shell命令，如果调用成功，不返回任何值，失败返回-1
                    execl("/bin/mount", "mount", userMount, mountBuf, "-o", "codepage=936,iocharset=utf8,uid=1000,gid=1000", NULL);
                    exit(0);
                } else {
//                    waitpid(-1, &waitStatus, NULL);
                    msleep(200);
                    if (child < 0)
                    {
                        bmount = false;
                    } else {
                        ncount = -1;
                        QDir mountDir(mountPath);
                        QFileInfoList list = mountDir.entryInfoList();
                        if (list.count() > 2)
                        {
                            mountPathList.append(mountPath);
                            emit usbChange(0, mountPath);
                        } else {
                            emit usbChange(-1, "");
                        }
                    }
                }
            }

//            sleep(5);                       //ivan这里应该用线程处理,或者将检测到的先保存，转换工作由线程统一处理
//            if(getmount(driver, mount))
//            {
//                emit usbChange(0, mount);
//            }

        }

    }

//    sleep(1);
#else
    return;
#endif
}

int UsbMonitor::initsock(void)
{
#ifdef Q_OS_LINUX
    struct sockaddr_nl snl;
    const int buffersize = 16 * 1024 * 1024;
    int retval;
    memset(&snl, 0x00, sizeof(struct sockaddr_nl));
    snl.nl_family = AF_NETLINK;
    snl.nl_pid = getpid();
    snl.nl_groups = 1;
    int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (hotplug_sock == -1)
    {
        //printf("error getting socket: %s", strerror(errno));
        return -1;
    }
    /* set receive buffersize */
    setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
    retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
    if (retval < 0)
    {
        //printf("bind failed: %s", strerror(errno));
        close(hotplug_sock);
        hotplug_sock = -1;
        return -1;
    }

    return hotplug_sock;
#else
    return -1;
#endif
}

bool UsbMonitor::getdriver(const char* NLmsg, char* driver)
{
    if(NLmsg == NULL || driver == NULL)
    {
        return false;
    }

    if(!memcmp(NLmsg,"add@",4))//对插入事件进行处理
    {
        char  ch = 'a';
        while(ch <= 'z')
        {
            for(int i=1; i<=10; i++)
            {
                char usb[50] = {0};
                sprintf(usb, "sd%c%d", ch, i);
                  if(strstr(NLmsg, usb) !=NULL)
                {
                   sprintf(driver, "/dev/%s", usb);
                   return true;
                }
            }

            ch++;
        }
    }

    return false;
}

//本函数需在系统自动加载成功后调用才能获取成功
bool UsbMonitor::getmount(const char* driver, char* mount)
{
    if(driver == NULL || mount == NULL)
    {
        return false;
    }

    FILE *fd = NULL;
    int len = 0;
//    int i = 0;
    //char buf[1024] = {0}; //ivan 事实证明1024是不够用的
    char buf[2048] = {0};
    char *seek = NULL;

    fd = fopen("/proc/mounts", "r");
    if(fd > 0)
    {
        len = fread(buf, 1, sizeof(buf), fd);
        fclose(fd);
        if (len > 0)
        {
            buf[len] = '\0';
            seek = strstr(buf, driver);
            if (seek != NULL)
            {
                seek += strlen(driver);
                while(*seek == ' ')     //定位到mount的开头
                {
                    seek++;
                }

                char* pos = seek;
                while(*seek != ' ')
                {
                    seek++;
                }
                *seek = '\0';

                strcpy(mount, pos);

                return true;
            }
            else
            {
               // printf("not found\n");
            }
        }
    }
    else
    {
        //printf("open error");
    }

    return false;
}

void UsbMonitor::run()
{
    this->usbmonitor();
}
